﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;

namespace UFrame
{
    /// <summary>
    /// 显示一个实体类
    /// </summary>
    public class PLEditorTool
    {
        private static string HandleCopyPaste(int controlID)
        {
            if (controlID == GUIUtility.keyboardControl)
            {
                if (Event.current.type == EventType.KeyUp &&
                    (Event.current.modifiers == EventModifiers.Control ||
                     Event.current.modifiers == EventModifiers.Command))
                {
                    if (Event.current.keyCode == KeyCode.C)
                    {
                        Event.current.Use();
                        TextEditor editor =
                            (TextEditor)GUIUtility.GetStateObject(typeof(TextEditor), GUIUtility.keyboardControl);
                        editor.Copy();
                    }
                    else if (Event.current.keyCode == KeyCode.V)
                    {
                        Event.current.Use();
                        TextEditor editor =
                            (TextEditor)GUIUtility.GetStateObject(typeof(TextEditor), GUIUtility.keyboardControl);
                        editor.Paste();
#if UNITY_5_3_OR_NEWER || UNITY_5_3
                        return editor.text; //以及更高的unity版本中editor.content.text已经被废弃，需使用editor.text代替
#else
                    return editor.content.text;
#endif
                    }
                    else if (Event.current.keyCode == KeyCode.A)
                    {
                        Event.current.Use();
                        TextEditor editor =
                            (TextEditor)GUIUtility.GetStateObject(typeof(TextEditor), GUIUtility.keyboardControl);
                        editor.SelectAll();
                    }
                }
            }

            return null;
        }

        /// <summary>
        /// TextField复制粘贴的实现
        /// </summary>
        public static string TextField(string value, params GUILayoutOption[] options)
        {
            int textFieldID = GUIUtility.GetControlID("TextField".GetHashCode(), FocusType.Keyboard) + 1;
            if (textFieldID == 0)
            {
                return value;
            }

            //处理复制粘贴的操作
            value = HandleCopyPaste(textFieldID) ?? value;

            return GUILayout.TextField(value, options);
        }


        public static bool ShowClassBox(object obj, DisplayClassSet set = null)
        {
            if (obj == null)
            {
                return false;
            }

            if (set == null)
            {
                set = new DisplayClassSet();
            }

            BindingFlags bf = BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly;

            if (set.isPrivate)
            {
                bf |= BindingFlags.NonPublic;
            }

            if (set.isStatic)
            {
                bf |= BindingFlags.Static;
            }

            var type = obj.GetType();
            var fieldAry = type.GetFields(bf);
            bool modify = false;
            for (int i = 0; i < fieldAry.Length; i++)
            {
                FieldInfo info = fieldAry[i];
                if (set.NoDisplayMember.Contains(info.Name))
                {
                    continue;
                }

                var fieldAttribute = info.GetCustomAttribute<PLFieldSelect>();

                object origin = info.GetValue(obj);
                object o = SwitchBox(info.Name, origin, info, fieldAttribute);

                modify = (origin == null && o != null) || (origin != null && origin.Equals(o) == false);
                set.SetModify(info.Name, modify);

                info.SetValue(obj, o);
            }

            return modify;
        }

        private static object SwitchBox(string name, object value, FieldInfo info, PLFieldSelect attribute)
        {
            string fieldName = info.FieldType.Name;
            if (info.FieldType.IsGenericType)
            {
                Type[] t = info.FieldType.GenericTypeArguments;
                fieldName = t[0].Name;
            }

            object val = null;
            if (attribute != null)
            {
                val = ComplexBox(name, value, info, fieldName, attribute);
            }
            else
            {
                val = BasicBox(name, value, info, fieldName);
            }

            return val;
        }

        private static object ComplexBox(string name, object value, FieldInfo info, string fieldName,
            PLFieldSelect attribute)
        {
            if (attribute != null)
            {
                string[] strAry = attribute.strAry;
                if (attribute.strAry == null)
                {
                    strAry = new[] { "特性中没有设置列表" };
                }

                int index = 0;
                for (int i = 0; i < strAry.Length; i++)
                {
                    if (strAry[i] == (string)value)
                    {
                        index = i;
                    }
                }

                index = EditorGUILayout.Popup(name, index, strAry);
                return strAry[index];
            }

            return null;
        }

        private static object BasicBox(string name, object value, FieldInfo info, string fieldName)
        {
            if (info.FieldType.IsEnum)
            {
                return EditorGUILayout.EnumPopup(name, value as Enum);
            }

            if (fieldName == "string" || fieldName == "String")
            {
                return EditorGUILayout.TextField(name, value as string);
            }
            else if (fieldName == "Int32")
            {
                return EditorGUILayout.IntField(name, Convert.ToInt32(value));
            }
            else if (fieldName == "Float" || fieldName == "Single")
            {
                return EditorGUILayout.FloatField(name, Convert.ToSingle(value));
            }
            else if (fieldName == "Double")
            {
                return EditorGUILayout.DoubleField(name, Convert.ToDouble(value));
            }
            else if (fieldName == "Enum")
            {
                return EditorGUILayout.EnumPopup(name, (Enum)value);
            }
            else if (fieldName == "Boolean" || value is bool)
            {
                return EditorGUILayout.Toggle(name, (bool)value);
            }

            return null;
        }
    }

    /// <summary>
    /// 负责布局辅助信息, 包括返回值
    /// </summary>
    public class DisplayClassSet
    {
        public bool isPrivate = false;
        public bool isStatic = false;
        public string[] NoDisplayMember = new String[] { "" };
        public Dictionary<string, bool> modifyDic = new Dictionary<string, bool>();
        public Dictionary<string, Action<object>> modifyActionDic = new Dictionary<string, Action<object>>();

        public bool IsModify(string fieldName)
        {
            return modifyDic.ContainsKey(fieldName) && modifyDic[fieldName];
        }

        public void SetModify(string fieldName, bool value)
        {
            if (modifyDic.ContainsKey(fieldName))
            {
                modifyDic[fieldName] = value;
            }
            else
            {
                modifyDic.Add(fieldName, value);
            }
        }
    }

    public class PLFieldSelect : Attribute
    {
        public Type o;
        public object target;
        public List<string> strlist;
        public string[] strAry;


        public PLFieldSelect(Type type)
        {
            o = type;
        }


        public PLFieldSelect(object target)
        {
            this.target = target;
        }


        public PLFieldSelect()
        {
        }

        public PLFieldSelect(List<string> target)
        {
            this.target = target;
            strAry = target.ToArray();
        }

        public PLFieldSelect(params string[] strAry)
        {
            this.strAry = strAry;
        }
    }
}